A complete, annotated guide to HTML5, CSS & PHP — written for programmers who already think in code and just need the syntax.
What you'll learn in this guide
HyperText Markup Language — the skeleton of every webpage
Every HTML5 page follows this skeleton. Tags are elements; most have an opening <tag> and closing </tag>.
HTML<!-- This is an HTML comment --> <!DOCTYPE html> <!-- Declares HTML5 (not a tag, a declaration) --> <html lang="en"> <!-- Root element --> <head> <!-- Meta info; NOT displayed on page --> <meta charset="UTF-8"> <!-- Self-closing tag (no / needed in HTML5) --> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Page Title</title> <link rel="stylesheet" href="style.css"> <!-- External CSS --> </head> <body> <!-- Everything visible goes here --> <h1>Hello, World!</h1> <script src="app.js"></script> <!-- JS at BOTTOM for performance --> </body> </html>
Semantic tags describe meaning, not appearance. They help SEO, accessibility, and readability. Use them instead of generic <div> everywhere.
| Element | Meaning | Replaces |
|---|---|---|
| <header> | Site or section header | <div id="header"> |
| <nav> | Navigation links | <div id="nav"> |
| <main> | Primary page content | <div id="main"> |
| <article> | Self-contained piece (blog post, card) | <div class="post"> |
| <section> | Thematic grouping with heading | <div class="section"> |
| <aside> | Sidebar / related content | <div id="sidebar"> |
| <footer> | Page or section footer | <div id="footer"> |
| <figure> | Image + caption wrapper | <div class="img-wrap"> |
| <time> | Date/time (machine-readable) | <span> |
| <mark> | Highlighted text | <span class="hl"> |
HTML<!-- Headings: h1 (most important) → h6 (least) --> <h1>Main Title</h1> <h2>Sub</h2> <h3>Sub-sub</h3> <p>A paragraph. Use <strong>bold</strong> and <em>italic</em>.</p> <!-- Anchor (link): href= destination, target= opens new tab --> <a href="https://example.com" target="_blank" rel="noopener">Visit</a> <!-- Image: src= path, alt= fallback text (REQUIRED for a11y) --> <img src="photo.jpg" alt="A cat sitting on a keyboard" width="400"> <br> <!-- line break (use sparingly) --> <hr> <!-- horizontal rule (thematic break) --> <span>inline container, no semantic meaning</span> <div>block container, no semantic meaning</div>
HTML<!-- Unordered list (bullets) --> <ul> <li>Apple</li> <li>Banana</li> </ul> <!-- Ordered list (numbers) --> <ol type="A" start="3"> <!-- type: 1 A a I i | start= offset --> <li>Step one</li> </ol> <!-- Description list (key→value pairs) --> <dl> <dt>HTML</dt> <dd>HyperText Markup Language</dd> </dl> <!-- Table --> <table> <thead> <tr><th>Name</th><th>Score</th></tr> </thead> <tbody> <tr><td>Alice</td><td>95</td></tr> <tr><td colspan="2">Total: 95</td></tr> <!-- spans 2 cols --> </tbody> </table>
Forms collect user input and send it to a server. action= is the PHP file that processes it; method= is GET (URL params) or POST (hidden in body).
HTML<!-- action= where data goes | method= GET or POST --> <form action="process.php" method="POST" enctype="multipart/form-data"> <!-- Text input --> <label for="uname">Username:</label> <input type="text" id="uname" name="username" placeholder="Enter name" required minlength="3"> <!-- Other input types: --> <input type="email" name="email"> <!-- validates @ format --> <input type="password" name="pass"> <!-- hides characters --> <input type="number" name="age" min="0" max="120"> <input type="date" name="dob"> <input type="checkbox" name="agree" value="yes"> <input type="radio" name="gender" value="m"> Male <input type="file" name="avatar" accept="image/*"> <!-- Dropdown --> <select name="country"> <option value="">-- Choose --</option> <option value="us">United States</option> </select> <!-- Multi-line text --> <textarea name="bio" rows="4" cols="40"></textarea> <button type="submit">Submit</button> </form>
HTML<!-- Video (native, no Flash needed) --> <video width="640" controls autoplay muted loop poster="thumb.jpg"> <source src="video.mp4" type="video/mp4"> <source src="video.webm" type="video/webm"> Your browser doesn't support video. </video> <!-- Audio --> <audio controls preload="metadata"> <source src="track.mp3" type="audio/mpeg"> </audio> <!-- Canvas (drawn via JavaScript) --> <canvas id="myCanvas" width="400" height="200"></canvas> <!-- iFrame embed (YouTube, maps, etc.) --> <iframe src="https://www.youtube.com/embed/VIDEO_ID" width="560" height="315" allowfullscreen></iframe>
Cascading Style Sheets — the skin and layout of every webpage
Specificity determines which rule wins when multiple rules target the same element. Higher = wins.
| Selector | Example | Specificity |
|---|---|---|
| element | h1 { } | 0-0-1 (lowest) |
| .class | .card { } | 0-1-0 |
| [attr] | input[type="text"] { } | 0-1-0 |
| :pseudo-class | a:hover { } | 0-1-0 |
| ::pseudo-element | p::first-line { } | 0-0-1 |
| #id | #hero { } | 1-0-0 |
| inline style | style="color:red" | 1-0-0-0 |
| !important | color: red !important | Overrides all ⚠️ |
CSSdiv p { } /* descendant: any p inside div */ div > p { } /* child: direct p children only */ h1 + p { } /* adjacent sibling: p immediately after h1 */ h1 ~ p { } /* general sibling: all p after h1 */ a, button { } /* group: applies to both a AND button */
Every HTML element is a rectangular box with four layers. box-sizing: border-box (recommended) makes width include padding and border.
CSS.box { box-sizing: border-box; width: 300px; height: 200px; padding: 16px; /* all 4 sides */ padding: 8px 16px; /* top/bot left/right */ margin: 0 auto; /* center horizontally */ border: 2px solid red; border-radius: 8px; }
Flex arranges items in a row or column. Parent holds the container properties; children get item properties.
CSS/* PARENT (container) */ .parent { display: flex; /* activates flex */ flex-direction: row; /* row | row-reverse | column | column-reverse */ justify-content: space-between; /* main axis: flex-start center end space-around */ align-items: center; /* cross axis: stretch flex-start flex-end */ flex-wrap: wrap; /* allow wrapping to new row */ gap: 1rem; /* spacing between items */ } /* CHILDREN (items) */ .item { flex: 1 1 200px; /* grow shrink basis */ align-self: flex-end; /* override align-items for this item */ order: 2; /* reorder without changing HTML */ }
Grid places items on both rows AND columns simultaneously — ideal for full-page layouts.
CSS.parent { display: grid; grid-template-columns: repeat(3, 1fr); /* 3 equal columns */ grid-template-columns: 200px 1fr 2fr; /* mixed widths */ grid-template-rows: auto 1fr auto; gap: 1rem; /* row-gap and column-gap */ } .span-two { grid-column: span 2; /* takes 2 column slots */ grid-row: 1 / 3; /* from row line 1 to 3 */ } /* Named template areas */ .layout { grid-template-areas: "header header" "sidebar content" "footer footer"; } header { grid-area: header; }
CSS/* Color formats */ color: red; /* named */ color: #ff0000; /* hex */ color: rgb(255, 0, 0); /* RGB */ color: rgba(255, 0, 0, 0.5); /* RGBA (50% opacity) */ color: hsl(0, 100%, 50%); /* Hue Saturation Lightness */ /* Gradients */ background: linear-gradient(135deg, #f06 0%, #60c8f0 100%); background: radial-gradient(circle, #fff 0%, #000 100%); /* CSS Custom Properties (variables) */ :root { --primary: #3b82f6; /* define with -- prefix */ } .btn { background: var(--primary); } /* use with var() */ /* Typography */ body { font-family: 'Georgia', serif; /* fallback stack */ font-size: 1rem; /* 1rem = 16px by default */ font-weight: 400; /* 100 thin → 900 black */ line-height: 1.6; /* unitless = × font-size */ letter-spacing: .05em; text-transform: uppercase; }
CSS/* TRANSITION — smooth change on state/class change */ .btn { background: blue; transition: background .3s ease, transform .2s; /* property duration easing */ } .btn:hover { background: navy; transform: scale(1.05); } /* KEYFRAME ANIMATION */ @keyframes pulse { 0% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.1); opacity: .7; } 100% { transform: scale(1); opacity: 1; } } .badge { animation: pulse 2s ease-in-out infinite; /* name dur easing iteration-count */ } /* TRANSFORM functions */ transform: translate(20px, -10px) /* move X, Y */ rotate(45deg) /* spin */ scale(1.5) /* resize */ skew(10deg); /* slant */
Media queries apply CSS rules only when conditions are met. Design mobile-first: write base styles for small screens, then add overrides for larger ones.
CSS/* Mobile-first breakpoints */ /* Base styles (mobile, 0px+) */ .grid { grid-template-columns: 1fr; } @media (min-width: 640px) { /* tablet */ .grid { grid-template-columns: repeat(2, 1fr); } } @media (min-width: 1024px) { /* desktop */ .grid { grid-template-columns: repeat(3, 1fr); } } /* Other media features */ @media (prefers-color-scheme: dark) { /* dark mode */ } @media (orientation: landscape) { /* landscape */ } @media (hover: none) { /* touch device */ } @media print { /* printer styles */ }
Hypertext Preprocessor — server-side scripting for dynamic pages
.php. PHP code lives between <?php and ?> tags.
The server executes the PHP, then sends plain HTML to the browser.
You need XAMPP / LAMP / WAMP locally, or a hosting provider, to run PHP files.
PHP<?php // Variables start with $ — dynamically typed $name = "Alice"; // string (single OR double quotes) $age = 30; // integer $gpa = 3.8; // float $active = true; // boolean (true / false) $nothing = null; // null // Type juggling and checking gettype($age); // "integer" is_string($name); // true (int) "42abc"; // cast to 42 // Operators $sum = 5 + 3; // + - * / % ** (** = exponent) $str = "Hello" . " World"; // . = string concatenation $str .= "!"; // .= append shorthand // Comparison 5 == "5" // true (loose: only value) 5 === "5" // false (strict: value AND type) 5 != 6 // true 5 <=> 6 // -1 (spaceship: <0, 0, >0) // Null coalescing (PHP 7+) $user = $_GET['user'] ?? "Guest"; // if null, use "Guest" ?>
PHP<?php $name = "World"; echo "Hello, $name!"; // variables expand in double quotes echo "Hello, {$name}s!"; // {} for complex expressions echo 'Hello, $name'; // single quotes: NO interpolation print "Hello"; // like echo, returns 1 // Heredoc (multi-line, interpolates variables) echo <<<EOT <p>Name: $name</p> <p>This can span lines.</p> EOT; // Common string functions strlen($name); // length: 5 strtoupper($name); // WORLD strtolower($name); // world str_replace("o", "0", $name); // W0rld trim(" hi "); // removes whitespace explode(",", "a,b,c"); // ["a","b","c"] — split to array implode("-", ["a","b"]); // "a-b" — join array htmlspecialchars($input); // ALWAYS escape user input! ?>
PHP<?php // if / elseif / else if ($age >= 18) { echo "Adult"; } elseif ($age >= 13) { echo "Teen"; } else { echo "Child"; } // Ternary shorthand $label = ($age >= 18) ? "Adult" : "Minor"; // switch switch ($day) { case "Mon": echo "Monday"; break; default: echo "Other day"; } // match expression (PHP 8 — strict, no fall-through) $result = match($status) { 1 => "Active", 0, -1 => "Inactive", default => "Unknown", }; // Loops for ($i = 0; $i < 5; $i++) { echo $i; } while ($x > 0) { $x--; } // check before each iteration do { $x--; } while ($x > 0); // always runs once foreach ($array as $key => $value) { echo "$key: $value"; // iterates arrays/objects } ?>
PHP<?php // Indexed array $fruits = ["apple", "banana", "cherry"]; echo $fruits[0]; // apple (0-indexed) $fruits[] = "date"; // append // Associative array (like a dictionary/hash map) $person = [ "name" => "Alice", "age" => 30, "email" => "alice@example.com", ]; echo $person["name"]; // Alice // Multidimensional array $users = [ ["name" => "Alice", "age" => 30], ["name" => "Bob", "age" => 25], ]; echo $users[1]["name"]; // Bob // Array functions count($fruits); // 4 array_push($fruits, "elderberry"); array_pop($fruits); sort($fruits); // alphabetical in_array("apple", $fruits); // true array_map(fn($f) => strtoupper($f), $fruits); // PHP 7.4 arrow fn array_filter($fruits, fn($f) => strlen($f) > 5); ?>
PHP<?php // Basic function function greet(string $name, string $greeting = "Hello"): string { return "$greeting, $name!"; } echo greet("Alice"); // "Hello, Alice!" echo greet("Bob", "Hi"); // "Hi, Bob!" // Named arguments (PHP 8) greet(greeting: "Hey", name: "Carol"); // Variadic (spread) arguments function sum(int ...$nums): int { return array_sum($nums); } // Anonymous function (closure) $double = function(int $n): int { return $n * 2; }; // Arrow function (PHP 7.4+) $triple = fn(int $n): int => $n * 3; ?>
PHP<?php // PHP superglobals (always available, any scope) $_GET // URL params: ?name=Alice $_POST // Form data: method="POST" $_FILES // Uploaded files $_SESSION // Persistent across page loads (need session_start()) $_COOKIE // Browser cookies $_SERVER // Server info: IP, request method, URI… $_ENV // Environment variables // Safe form handler pattern if ($_SERVER['REQUEST_METHOD'] === 'POST') { // 1. Retrieve $name = $_POST['name'] ?? ''; $email = $_POST['email'] ?? ''; // 2. Sanitize $name = htmlspecialchars(strip_tags(trim($name))); $email = filter_var($email, FILTER_SANITIZE_EMAIL); // 3. Validate if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $error = "Invalid email"; } // 4. Use (store, email, redirect…) if (empty($error)) { header("Location: thankyou.php"); // redirect exit; } } ?>
PDO (PHP Data Objects) provides a safe, database-agnostic way to run SQL queries. Always use prepared statements to prevent SQL injection.
PHP<?php // 1. Connect $dsn = "mysql:host=localhost;dbname=myapp;charset=utf8mb4"; $pdo = new PDO($dsn, 'root', 'password', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]); // 2. CREATE TABLE (run once) $pdo->exec(" CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(150) NOT NULL UNIQUE ) "); // 3. INSERT with prepared statement (:placeholder syntax) $stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (:name, :email)"); $stmt->execute([':name' => $name, ':email' => $email]); $newId = $pdo->lastInsertId(); // 4. SELECT all rows $rows = $pdo->query("SELECT * FROM users ORDER BY name")->fetchAll(); foreach ($rows as $row) { echo "<li>{$row['name']} — {$row['email']}</li>"; } // 5. SELECT one row $stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id"); $stmt->execute([':id' => 1]); $user = $stmt->fetch(); ?>
A complete 3-file website bringing it all together
php -S localhost:8000 in terminal). Visit
http://localhost:8000/index.php.
PHP + HTML<?php // Include shared config (db connection, functions) require_once 'config.php'; // Handle form submission $message = ''; $error = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $name = sanitize($_POST['name'] ?? ''); $email = sanitize($_POST['email'] ?? ''); if (empty($name) || empty($email)) { $error = "All fields are required."; } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $error = "Please enter a valid email."; } else { // Save to DB $stmt = $pdo->prepare( "INSERT INTO greetings (name, email) VALUES (:name, :email)" ); $stmt->execute([':name' => $name, ':email' => $email]); $message = "Hello, $name! You're registered."; } } // Fetch all greetings for display $greetings = $pdo->query("SELECT * FROM greetings ORDER BY id DESC")->fetchAll(); ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>Hello World</title> <link rel="stylesheet" href="style.css"> </head> <body> <header> <h1>Hello, World!</h1> <p>HTML5 + CSS + PHP Demo Site</p> </header> <main> <!-- PHP output inside HTML --> <?php if ($message): ?> <div class="alert alert-success"><?= $message ?></div> <?php endif; ?> <?php if ($error): ?> <div class="alert alert-error"><?= $error ?></div> <?php endif; ?> <section class="card"> <h2>Register</h2> <form method="POST" action=""> <!-- action="" = same page --> <label for="name">Name</label> <input type="text" id="name" name="name" required value="<?= htmlspecialchars($name ?? '') ?>"> <label for="email">Email</label> <input type="email" id="email" name="email" required> <button type="submit">Say Hello!</button> </form> </section> <section class="card"> <h2>Greetings Log</h2> <ul> <?php foreach ($greetings as $g): ?> <li><strong><?= htmlspecialchars($g['name']) ?></strong> — <?= htmlspecialchars($g['email']) ?></li> <?php endforeach; ?> </ul> </section> </main> <footer> <p>© <?= date('Y') ?> My Hello World Site</p> </footer> </body> </html>
PHP<?php // Database credentials (move to .env in production!) define('DB_HOST', 'localhost'); define('DB_NAME', 'helloworld'); define('DB_USER', 'root'); define('DB_PASS', ''); // PDO connection try { $pdo = new PDO( "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4", DB_USER, DB_PASS, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION] ); // Create table if it doesn't exist $pdo->exec(" CREATE TABLE IF NOT EXISTS greetings ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(150) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) "); } catch (PDOException $e) { die("DB Error: " . $e->getMessage()); } // Reusable helper function function sanitize(string $input): string { return htmlspecialchars(strip_tags(trim($input))); } ?>
CSS/* ── Base ── */ * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'Segoe UI', sans-serif; background: #f5f7fa; color: #2d2d2d; line-height: 1.6; } /* ── Header ── */ header { background: linear-gradient(135deg, #1a1a2e, #16213e); color: white; text-align: center; padding: 3rem 1rem; } header h1 { font-size: clamp(2rem, 5vw, 3.5rem); } /* ── Main ── */ main { max-width: 760px; margin: 2rem auto; padding: 0 1rem; } /* ── Cards ── */ .card { background: white; border-radius: 12px; box-shadow: 0 2px 16px rgba(0,0,0,.08); padding: 2rem; margin-bottom: 1.5rem; } /* ── Form ── */ label { display: block; margin: .75rem 0 .25rem; font-weight: 600; } input, select, textarea { width: 100%; border: 1px solid #ccc; border-radius: 6px; padding: .55rem .85rem; font-size: 1rem; transition: border-color .2s; } input:focus, select:focus, textarea:focus { outline: none; border-color: #3b82f6; box-shadow: 0 0 0 3px rgba(59,130,246,.2); } button[type="submit"] { margin-top: 1rem; background: #3b82f6; color: white; border: none; border-radius: 6px; padding: .65rem 1.5rem; font-size: 1rem; font-weight: 600; cursor: pointer; transition: background .2s; } button:hover { background: #2563eb; } /* ── Alerts ── */ .alert { padding: 1rem; border-radius: 8px; margin-bottom: 1rem; } .alert-success { background: #dcfce7; color: #166534; border: 1px solid #86efac; } .alert-error { background: #fee2e2; color: #991b1b; border: 1px solid #fca5a5; } /* ── List ── */ .card ul { padding-left: 1.2rem; } .card li { padding: .3rem 0; border-bottom: 1px solid #f0f0f0; } /* ── Footer ── */ footer { text-align: center; padding: 2rem; color: #888; font-size: .875rem; } /* ── Responsive ── */ @media (max-width: 480px) { .card { padding: 1.25rem; } header h1 { font-size: 2rem; } }